Skip to content

Potential fix for code scanning alert no. 6: Unvalidated dynamic method call#21

Merged
ialejandro merged 2 commits intomainfrom
fix/alert-autofix-6
Feb 15, 2026
Merged

Potential fix for code scanning alert no. 6: Unvalidated dynamic method call#21
ialejandro merged 2 commits intomainfrom
fix/alert-autofix-6

Conversation

@ialejandro
Copy link
Member

Potential fix for https://github.com/devops-ia/self-learning-platform/security/code-scanning/6

General approach: Keep dynamic command handling but ensure that any function we call is (a) associated with an allowed command string, (b) an own property of the commands map (not from the prototype chain), and (c) actually a function. Also avoid calling handlers multiple times or without consistent validation.

Best concrete fix while preserving behavior:

  1. Keep the existing hasOwnProperty + typeof === "function" checks for exact matches.
  2. For the prefix-matching loop, avoid iterating over potentially inherited properties and avoid calling handlers without ensuring they are functions and own properties. We already get own properties from Object.entries, but to address the CodeQL concern and make the flow clearer, we can reuse the same validation pattern as for the exact match.
  3. Unify the handler selection logic: first resolve a validated handler (exactHandler or prefixHandler), then call it once. This keeps behavior the same but centralizes validation and the call site, making the sink easier to reason about.

Concretely in src/lib/terminal/simulator.ts:

  • Introduce a local let handlerToExecute: ((code: string) => TerminalResponse) | undefined and populate it either from the exact match or from the prefix loop, only when the value is a function.
  • After those selection steps, check if (handlerToExecute) and call it exactly once.
  • Inside the prefix loop, we already have typeof handler !== "function" and Object.entries (which yields own enumerable properties), so the main behavioral change is to assign the chosen handler to handlerToExecute instead of invoking it directly; this helps keep all invocations going through a single, validated call site.

No changes are needed in src/app/api/terminal/route.ts.

Suggested fixes powered by Copilot Autofix. Review carefully before merging.

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
Signed-off-by: Iván Alejandro Marugán <hello@ialejandro.rocks>
@ialejandro ialejandro marked this pull request as ready for review February 15, 2026 15:35
return handler(currentCode);
}
if (handlerToExecute) {
return handlerToExecute(currentCode);

Check failure

Code scanning / CodeQL

Unvalidated dynamic method call High

Invocation of method with
user-controlled
name may dispatch to unexpected target and cause an exception.

Copilot Autofix

AI 5 days ago

In general, to fix this kind of issue you must ensure that user-controlled strings cannot arbitrarily select or invoke unexpected methods. This is typically done by (a) restricting dispatch to a known whitelist of commands, (b) verifying that the selected value is an own property and a function, and (c) avoiding overly permissive matching logic that might invoke commands on partial matches in surprising ways. It’s also good practice to handle exceptions from invoked handlers so one bad handler or input cannot take down the whole endpoint.

For this specific code, the essential parts are already in place: an own-property check and a typeof === "function" check. The main remaining concerns are: (1) the looser prefix-matching path, and (2) the lack of a safety net around the handler call. To keep current behavior while improving safety, we can:

  1. Keep the exact-match logic as is (it already validates own property and function type).
  2. Keep the prefix-matching logic but explicitly ensure we’re only iterating over own properties (using Object.entries is fine) and already checking typeof handler === "function"; that’s good.
  3. Add a defensive guard before invocation to verify typeof handlerToExecute === "function" right at the call site; this guards against future changes where handlerToExecute might accidentally be set to a non-function.
  4. Wrap the invocation in a try/catch block so unexpected exceptions from handler code cannot crash the API; instead, return a controlled error message and non-zero exit code. This directly mitigates the DoS angle CodeQL is concerned about, without changing which commands are permitted.

All necessary changes are in src/lib/terminal/simulator.ts, around the final check and invocation of handlerToExecute. No import changes or new helper functions are required.


Suggested changeset 1
src/lib/terminal/simulator.ts

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/lib/terminal/simulator.ts b/src/lib/terminal/simulator.ts
--- a/src/lib/terminal/simulator.ts
+++ b/src/lib/terminal/simulator.ts
@@ -48,8 +48,15 @@
     }
   }
 
-  if (handlerToExecute) {
-    return handlerToExecute(currentCode);
+  if (typeof handlerToExecute === "function") {
+    try {
+      return handlerToExecute(currentCode);
+    } catch (error) {
+      return {
+        output: `Error: command execution failed`,
+        exitCode: 1,
+      };
+    }
   }
 
   // Built-in commands
EOF
@@ -48,8 +48,15 @@
}
}

if (handlerToExecute) {
return handlerToExecute(currentCode);
if (typeof handlerToExecute === "function") {
try {
return handlerToExecute(currentCode);
} catch (error) {
return {
output: `Error: command execution failed`,
exitCode: 1,
};
}
}

// Built-in commands
Copilot is powered by AI and may make mistakes. Always verify output.
@ialejandro ialejandro merged commit 8cf2002 into main Feb 15, 2026
12 of 13 checks passed
@ialejandro ialejandro deleted the fix/alert-autofix-6 branch February 15, 2026 15:40
github-actions bot pushed a commit that referenced this pull request Feb 15, 2026
## [1.1.2](v1.1.1...v1.1.2) (2026-02-15)

### Bug Fixes

* Unvalidated dynamic method call ([#21](#21)) ([8cf2002](8cf2002)), closes [#22](#22)
@github-actions
Copy link

🎉 This PR is included in version 1.1.2 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

Comments